#自定义可迭代对象和迭代器
from collections.abc import Iterator, Iterable
#Iterable是否为可迭代对象，Iterator是否为迭代器
lst = [1, 2, 3]
iterator = iter(lst)

print(isinstance(lst, Iterable))		#判断列表对象是否为可迭代对象
print(isinstance(iterator, Iterator))	#判断列表的迭代器是否为迭代器
print(isinstance(iterator, Iterable))	#判断列表的迭代器是否为可迭代对象

#输出结果：
"""
TruE
TruE
TruE
"""
'''
#先看两个方法__iter__()和__next__()
class C(object):
    def __iter__(self):
        print('调用了一个__iter__方法')
        return #注意__iter__需要返回一个迭代器
    def __next__(self):
        print('调用了一个__next__方法')
        return 10#注意__next__可以返回一个数
'''
'''
class C:
    def __iter__(self):
        pass
    
exp=C()
print(isinstance(exp,Iterator))#False,不是迭代器
print(isinstance(exp,Iterable))#True，是可迭代对象
'''
#注意：iter函数的本质就是去自动调用__iter__方法，next函数的本质就是去自动调用__next__方法
class C:
    def __iter__(self):
        pass
    def __next__(self):
        pass

exp = C()
print(isinstance(exp, Iterator))  # TruE,是迭代器
print(isinstance(exp, Iterable))  # TruE，是可迭代对象
#说明：有__iter__和__next__方法的对象就是一个迭代器
'''
摘抄一下别人的笔记：
迭代器的本质就是一个同时具有__iter__方法和__next__方法的对象，而可迭代对象的本质就是一个具有__iter__方法的对象
可迭代对象和迭代器的关系为：可迭代对象不一定为一个迭代器，而迭代器必定是一个可迭代对象
'''
class ExpIterable:
    def __init__(self):
        self.list1=list()
        self.count=0
    def add(self,data):
        self.list1.append(data)
        self.count+=1
        print('成功添加数据{},现在内部共有{}个数据'.format(data,self.count))
    def delete(self,position):
        num=self.list1.pop(position)
        self.count-=1
        print('成功删除数据{},现在内部共有{}个数据'.format(num,self.count))
    def __iter__(self):
        return ExpIterator(self.list1)#调用iter函数时实际调用__iter__(),返回一个迭代器。这个迭代器需要能够执行next()操作，即需要有一个__next__()方法
#基于上面的表述，我们需要创建一个能够被视为迭代器（有__next__()方法）的类
#与此同时，在迭代器内部……
'''
class ExpIterator:
    #第一步，需要把可迭代对象传进来，对应了生成可迭代对象的迭代器的步骤
    def __init__(self,list2):
        self.list2=list2
        self.count=0
    #第二步，使用__next__()方法按照方法内部的定义把数据逐个取出，对应了外部逐渐迭代的步骤
    def  __next__(self,step=1):
        data = self.list2[self.count]#取出list2中count位置的数据
        self.count += step#让count加一，等待下一次迭代
        return data#返回取出的值
'''
class ExpIterator:
    #第一步，需要把可迭代对象传进来，对应了生成可迭代对象的迭代器的步骤
    def __init__(self,list2):
        self.list2=list2
        self.count=0
    #第二步，使用__next__()方法按照方法内部的定义把数据逐个取出，对应了外部逐渐迭代的步骤
    def  __next__(self,step=1):
        data = self.list2[self.count]#取出list2中count位置的数据
        self.count += step#让count加一，等待下一次迭代
        return data#返回取出的值
    def __iter__(self):
        return self#直接返回自身即可

c=ExpIterable()
for i in range(5):
    c.add(i)
print(c.list1)#[0, 1, 2, 3, 4]
ex_in=iter(c)#这一句本质是调用c.__iter__()，创建了一个名为ex_in的“迭代器”
#即：写ex_in=c.__iter__()效果是一样的
while True:
    try:
        print(ex_in.__next__(2))
        #写next(ex_in)是一样的，但是因为没法传参，只能默认上面的step=1
    except:
        print('迭代已结束')
        break
'''
0
1
2
3
4
迭代已结束
'''
ex_in_1=iter(ex_in)
print(ex_in_1)#<__main__.ExpIterator object at 0x00000207DBFD7B60>
print(ex_in)#<__main__.ExpIterator object at 0x00000207DBFD7B60>
#这样就实现了迭代器取迭代器还是本身
#观察到这样的现象：
list1=[1,2,3]
iter1=iter(list1)
print(iter1)#<list_iterator object at 0x000001E79A9FD210>
iter2=iter(list1)
print(iter2)#<list_iterator object at 0x000001E79A9FD2A0>
#对可迭代对象调用迭代器，每次调用的结果都不同，即创建了一个新的迭代器
print(next(iter1))
iter3=iter(iter1)#1
print(iter3)#<list_iterator object at 0x000001E79A9FD210>
print(next(iter3))#2
#对迭代器取迭代器，取到的是本身
#基于此，可以对上面的自制迭代器进行优化
